package Concurrency2.Chapter03_CAS_Atomic.P02_AtomicClassesUsage;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;

/**
 * 基本数据类型
 * 1, AtomicInteger
 * 2, AtomicLong
 * 3, AtomicBoolean
 * 性能对比: 内置锁 vs AtomicXxx vs LongAdder
 */
public class T01_BaseType {

    private static final int TURN = 1000000; //任务中的循环次数
    private static final int THREAD_COUNT = 10;
    private static CountDownLatch atomicCountdownLatch = new CountDownLatch(THREAD_COUNT);
    private static CountDownLatch innerLockCountdownLatch = new CountDownLatch(THREAD_COUNT);
    private static CountDownLatch longAdderCountdownLatch = new CountDownLatch(THREAD_COUNT);
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static long innerLockInteger = 0;

    public static void main(String[] args) {
        //方式1: 原子类测试性能
        testAtomicClassPerformance();
        //方式2: 内置锁测试性能
        testInnerLockPerformance();
        //方式3: LongAdder测试性能
        testLongAdderPerformance();
        // 关闭线程池
        threadPool.shutdownNow();
    }

    /**
     * 内置锁的性能测试
     */
    private static void testInnerLockPerformance() {
        long start = System.currentTimeMillis();
        Object lockObj = new Object(); //锁对象
        // 1, 创建任务定义
        Runnable innerLockTask = () -> {
            for (int i = 0; i < TURN; i++) {
                synchronized (lockObj) {
                    innerLockInteger++;
                }
            }
            innerLockCountdownLatch.countDown();
        };
        // 2, 提交任务给线程池
        submitTask(innerLockTask, innerLockCountdownLatch);
        long end = System.currentTimeMillis();
        // 3, 输出执行结果
        computePerformance("内置锁执行结果: ", innerLockInteger, "内置锁: -- 时间消耗: ", end, start);
    }

    /**
     * 原子类的性能测试
     */
    private static void testAtomicClassPerformance() {
        long start = System.currentTimeMillis();
        AtomicInteger atomicInteger = new AtomicInteger(0);
        // 1, 定义任务: 使用原子类自增
        Runnable atomicClassTask = () -> {
            for (int i = 0; i < TURN; i++) {
                atomicInteger.incrementAndGet();
            }
            atomicCountdownLatch.countDown();
        };
        // 2, 创建线程池, 提交任务
        submitTask(atomicClassTask, atomicCountdownLatch);
        long end = System.currentTimeMillis();
        // 3, 输出执行结果
        computePerformance("原子类执行结果: ", atomicInteger.get(), "原子类: -- 时间消耗: ", end, start);
    }

    /**
     * 使用LongAdder计算
     */
    private static void testLongAdderPerformance() {
        long start = System.currentTimeMillis();
        LongAdder longAdder = new LongAdder();
        // 1, 定义任务
        Runnable longAdderTask = () -> {
            for (int i = 0; i < TURN; i++) {
                longAdder.add(1);
            }
            longAdderCountdownLatch.countDown();
        };
        // 2, 提交任务
        submitTask(longAdderTask, longAdderCountdownLatch);
        // 3, 输出执行结果
        long end = System.currentTimeMillis();
        computePerformance("LongAdder执行结果: ", longAdder.sum(), "LongAdder: -- 时间消耗: ", end, start);
    }

    /**
     * 辅助方法1: 提交任务
     *
     * @param runnable       待提交的任务
     * @param countDownLatch 计数器
     */
    private static void submitTask(Runnable runnable, CountDownLatch countDownLatch) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.submit(runnable);
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 辅助方法2: 输出结果
     *
     * @param taskTypeMessage    任务信息
     * @param result             结果
     * @param performanceMessage 性能信息
     * @param start              执行开始时间戳
     * @param end                执行完成时间戳
     */
    private static void computePerformance(String taskTypeMessage, long result, String performanceMessage, long end, long start) {
        System.out.println(taskTypeMessage + result);
        System.out.println(performanceMessage + (end - start));
    }
}
